#ifndef MCPROXY_GENERAL_H
#define MCPROXY_GENERAL_H

#include <stddef.h>
#include <stdbool.h>

/* Number of connections to open */
#define DEFAULT_CONNECTIONS 1000

/* Number of simultaneous requests to send */
#define DEFAULT_REQUESTS 10

/* Size of our key space (determines cache hit rate) */
#define DEFAULT_KEYS 1000

/* Default time to wait for a response */
#define DEFAULT_POLL_WAIT_SEC 5

/* Default random seed */
#define DEFAULT_SEED 0

#define MAX_KEY_LEN (1024)
#define MAX_VAL_LEN (1024)

#define MAX_NUM_CLIENT  (4)
#define MAX_NUM_PROXY   (4)
#define MAX_NUM_SERVER  (4)
#define MAX_NUM_PORT    (4)
#define MAX_SERVER_LEN  (16)
#define MAX_GET_BUF_SIZE (512)
#define MAX_SET_BUF_SIZE (1024)

bool use_ascii_protocol;
bool enable_udp;

typedef struct _event_context {
    struct event_base *base;
    struct event *event_read;
    struct event *event_write;
} event_context;

typedef struct req_s {
    //int req_cmd; //assume ONLY get request
    //uint16_t server_rank;
    //uint16_t port;
    char *req;
    int len;
} req_t;

typedef struct req_circular_buffer {
    int tail;
    int head;
    req_t *rqs;
    int size;
} req_buf;

typedef struct _connection_info {
    char *server;
    int port;
    int rank;
    int sfd;
    //struct bufferevent *conn_bev;
} conn_info;

/*
typedef struct _proxy_conn_info {
    conn_info conn;
    req_buf rqs_in_buf;
    req_buf rqs_out_buf;

    char *sndbuf;
    int sndbufsize;
    int sndoff;
    int sndlen;

    char *rcvbuf;
    int rcvbufsize;
    int rcvstart;
    int rcvnext;

} proxy_conn_info;
 */

//client_conn_info client_conn[MAX_NUM_PROXY];
//proxy_conn_info  proxy_conn[MAX_NUM_SERVER * MAX_NUM_PORT];

/*
typedef struct _proxy_conn {
    conn_info **conn_list; //include client and server
    int num_conn;
    //int proxy_fd;
} proxy_conn_t;
proxy_conn_t proxy_conn;
 */

/*
typedef struct _conn_context {
    //event_context *event_ctx;
    conn_info *conn;
} conn_context;
 */

typedef struct _queue_buffer {
    char *buf;
    size_t buf_len;
    int buf_offset;
    int num_rqs;
} queue_buf;

typedef struct proxy_conn_with_buffer {
    conn_info conn;
    queue_buf q_buf;
} proxy_conn_w_buf;

typedef struct _proxy_conn_server_st {
    proxy_conn_w_buf **pcs_list;
    int num_s_conn;
} proxy_conn_server_list;

typedef struct _proxy_conn_client_st {
    conn_info **pcc_list;
    int num_c_conn;
} proxy_conn_client_list;

typedef struct bev_fd_map_entry_st {
    struct bufferevent *bev;
    int index;
    int mfd;
} bev_fd_map_entry;

typedef struct bev_fd_map_st {
    bev_fd_map_entry *entries;
    int num_entries;
} bev_fd_map;
bev_fd_map bf_map; //todo init

proxy_conn_client_list pcc_list; //todo init
proxy_conn_server_list pcs_list; //todo init

typedef struct proxy_to_client_st {
    conn_info *src_s_info;
    proxy_conn_client_list *dst_client;
    struct bufferevent **dst_c_bevs;
} proxy_to_client;

typedef struct proxy_to_server_st {
    conn_info *src_c_info;
    proxy_conn_server_list *dst_server;
    struct bufferevent **dst_s_bevs;
} proxy_to_server;

typedef struct {
    char *mc_clients[MAX_NUM_CLIENT];
    char *mc_proxys[MAX_NUM_PROXY];
    char *mc_servers[MAX_NUM_SERVER];
    //int mc_client_ports[MAX_NUM_PORT];
    int mc_proxy_ports[MAX_NUM_PORT];
    int mc_server_ports[MAX_NUM_PORT];
    int num_clients;
    int num_proxys;
    int num_servers;
    int num_conn_per_client;
    int num_proxy_ports;
    int num_server_ports;
} server_config;

server_config s_config; //todo init

#endif //MCPROXY_GENERAL_H
